import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import React, { useCallback, useMemo, useState } from 'react';
import { NodeProps } from 'reactflow';
import { useContextSelector } from 'use-context-selector';

import Slider from '@/components/Antd/Slider';
import CollapsibleSection from '@/components/CollapsibleSection';
import FormLabel from '@/components/MyBox/FormLabel';
import { t } from '@/locales/i18n';
import { FlowNodeTypeEnum, NodeInputKeyEnum, VARIABLE_NODE_ID } from '@/types/workflow/constant';
import { FlowNodeInputItemType, ReferenceValueProps } from '@/types/workflow/io';
import { FlowNodeItemType } from '@/types/workflow/node';
import { getOneQuoteInputTemplate } from '@/types/workflow/template/system/datasetConcat';
import { isWorkflowStartOutput } from '@/types/workflow/template/system/workflowStart';
import { getWebLLMModel } from '@/utils/system/utils';

import { WorkflowContext } from '../../context';

import NodeCard from './render/NodeCard';
import RenderInput from './render/RenderInput';
import { ReferSelector, useReference } from './render/RenderInput/templates/Reference';
import RenderOutput from './render/RenderOutput';
import ValueTypeLabel from './render/ValueTypeLabel';

const NodeDatasetConcat = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
  const { nodeId, inputs, outputs } = data;
  const { nodeList, onChangeNode } = useContextSelector(WorkflowContext, (v) => v);

  const [expandedSections, setExpandedSections] = useState<Set<'input' | 'output'>>(
    new Set(['input']),
  );

  const toggleSection = (section: 'input' | 'output') => {
    setExpandedSections((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(section)) {
        newSet.delete(section);
      } else {
        newSet.add(section);
      }
      return newSet;
    });
  };

  const CustomComponent = useMemo(() => {
    const quoteList = inputs.filter((item) => item.canEdit);
    const tokenLimit = (() => {
      let maxTokens = 13000;

      nodeList.forEach((item) => {
        if ([FlowNodeTypeEnum.chatNode, FlowNodeTypeEnum.tools].includes(item.flowNodeType)) {
          const model =
            item.inputs.find((item) => item.key === NodeInputKeyEnum.aiModel)?.value || '';
          const quoteMaxToken = getWebLLMModel(model)?.quoteMaxToken || 13000;

          maxTokens = Math.max(maxTokens, quoteMaxToken);
        }
      });

      return maxTokens;
    })();

    const Reference = ({
      nodeId,
      inputChildren,
    }: {
      nodeId: string;
      inputChildren: FlowNodeInputItemType;
    }) => {
      const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
      const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);

      const { referenceList, formatValue } = useReference({
        nodeId,
        valueType: inputChildren.valueType,
        value: inputChildren.value,
      });

      const onSelect = useCallback(
        (e: ReferenceValueProps) => {
          const workflowStartNode = nodeList.find(
            (node) => node.flowNodeType === FlowNodeTypeEnum.workflowStart,
          );

          onChangeNode({
            nodeId,
            type: 'replaceInput',
            key: inputChildren.key,
            value: {
              ...inputChildren,
              value:
                e[0] === workflowStartNode?.id && !isWorkflowStartOutput(e[1])
                  ? [VARIABLE_NODE_ID, e[1]]
                  : e,
            },
          });
        },
        [inputChildren, nodeId, nodeList, onChangeNode],
      );

      const onDel = useCallback(() => {
        onChangeNode({
          nodeId,
          type: 'delInput',
          key: inputChildren.key,
        });
      }, [inputChildren.key, nodeId, onChangeNode]);

      const Render = useMemo(() => {
        return (
          <>
            <div className="mb-1 flex items-center gap-2">
              <FormLabel required={inputChildren.required}>
                {t(inputChildren.label as any)}
              </FormLabel>
              <ValueTypeLabel
                valueType={inputChildren.valueType}
                valueDesc={inputChildren.valueDesc}
              />
              <Button
                className="delete cursor-pointer text-gray-600 hover:text-error"
                type="text"
                name="delete"
                danger
                onClick={onDel}
                icon={<DeleteOutlined />}
              />
            </div>
            <ReferSelector
              placeholder={t(
                (inputChildren.referencePlaceholder as any) ||
                  t('core.module.Dataset quote.select'),
              )}
              list={referenceList}
              value={formatValue}
              onSelect={onSelect}
            />
          </>
        );
      }, [
        formatValue,
        inputChildren.label,
        inputChildren.referencePlaceholder,
        inputChildren.required,
        inputChildren.valueDesc,
        inputChildren.valueType,
        onDel,
        onSelect,
        referenceList,
      ]);

      return Render;
    };

    return {
      [NodeInputKeyEnum.datasetMaxTokens]: ({ value, key, ...item }: FlowNodeInputItemType) => (
        <div className="mr-4 flex-1 pt-4">
          <Slider
            min={100}
            max={tokenLimit}
            step={50}
            defaultValue={value}
            onChangeComplete={(e) => {
              onChangeNode({
                nodeId,
                type: 'updateInput',
                key,
                value: {
                  ...item,
                  key,
                  value: e,
                },
              });
            }}
            tooltip={undefined}
          />
          <div className="flex justify-between text-xs text-text-3">
            <span>100</span>
            <span>{tokenLimit}</span>
          </div>
        </div>
      ),
      [NodeInputKeyEnum.datasetQuoteList]: (item: FlowNodeInputItemType) => {
        return (
          <>
            <div className="nodrag relative flex cursor-default">
              <div className="relative font-medium">
                <span>{t('core.workflow.Dataset quote')}</span>
              </div>
              <div className="flex-1" />
              <Button
                type="text"
                icon={<PlusOutlined />}
                size="small"
                onClick={() => {
                  onChangeNode({
                    nodeId,
                    type: 'addInput',
                    value: getOneQuoteInputTemplate({ index: quoteList.length + 1 }),
                  });
                }}
              />
            </div>
            <div className="mt-2">
              {quoteList.map((children, index) => (
                <div
                  className={`${index === quoteList.length - 1 ? '' : 'mb-3'}`}
                  key={children.key}
                >
                  <Reference nodeId={nodeId} inputChildren={children} />
                </div>
              ))}
            </div>
          </>
        );
      },
    };
  }, [inputs, nodeId, nodeList, onChangeNode]);

  const requireText = 'Tokens上限，知识库列表';

  const Render = useMemo(() => {
    return (
      <NodeCard minW="400px" selected={selected} {...data}>
        <div className="flex flex-col gap-3 space-y-0">
          <CollapsibleSection
            title={t('workflow.node.basic_config')}
            subtitle={`${t('workflow.node.basic_config_desc')}(${requireText})`}
            isExpanded={expandedSections.has('input')}
            onToggle={() => toggleSection('input')}
            type="input"
          >
            <RenderInput nodeId={nodeId} flowInputList={inputs} CustomComponent={CustomComponent} />
          </CollapsibleSection>
          <CollapsibleSection
            title={t('workflow.node.output')}
            subtitle={t('workflow.node.output_desc')}
            isExpanded={expandedSections.has('output')}
            onToggle={() => toggleSection('output')}
            type="output"
            className="pb-3"
          >
            <div className="max-h-[200px] overflow-y-auto px-2">
              <RenderOutput nodeId={nodeId} flowOutputList={outputs} />
            </div>
          </CollapsibleSection>
        </div>
      </NodeCard>
    );
  }, [CustomComponent, expandedSections, data, inputs, nodeId, outputs, selected]);

  return Render;
};
export default React.memo(NodeDatasetConcat);
